// --------------------------------------------------------------------------------------------------------------------
// <copyright file="NodeViewModel.cs" company="Akzente.IT">
//   (c) 2012 Akzente.IT
// </copyright>
// <summary>
//   The node view model.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace AkzenteIT.DatabaseDocumentationTool.ViewModels.Base
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;

    /// <summary>
    /// The node view model.
    /// </summary>
    public abstract class NodeViewModel : INotifyPropertyChanged
    {
        #region Fields

        /// <summary>
        /// The children.
        /// </summary>
        private ObservableCollection<NodeViewModel> children;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="NodeViewModel"/> class.
        /// </summary>
        /// <param name="parent">
        /// The parent.
        /// </param>
        public NodeViewModel(NodeViewModel parent)
        {
            this.Parent = parent;
        }

        #endregion

        #region Public Events

        /// <summary>
        /// The node updated.
        /// </summary>
        public event EventHandler NodeUpdated;

        /// <summary>
        /// The property changed.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets the children.
        /// </summary>
        public IEnumerable<NodeViewModel> Children
        {
            get
            {
                if (this.children == null)
                {
                    this.children = new ObservableCollection<NodeViewModel>();

                    var loadedItems = this.LoadChildren();

                    if (loadedItems != null)
                    {
                        foreach (var child in loadedItems)
                        {
                            child.NodeUpdated += this.ChildNodeUpdated;
                            this.children.Add(child);
                        }
                    }
                }

                return this.children;
            }
        }

        /// <summary>
        /// Gets a value indicating whether is category.
        /// </summary>
        public virtual bool IsCategory
        {
            get
            {
                return false;
            }
        }

        /// <summary>
        /// Gets the name.
        /// </summary>
        public abstract string Name { get; }

        /// <summary>
        /// Gets the owner.
        /// </summary>
        public virtual NodeViewModel Owner
        {
            get
            {
                return this.IsCategory ? this.Parent.Owner : this;
            }
        }

        /// <summary>
        /// Gets or sets the parent.
        /// </summary>
        public NodeViewModel Parent { get; set; }

        #endregion

        #region Public Methods and Operators

        /// <summary>
        /// The notify property changed.
        /// </summary>
        /// <param name="propName">
        /// The prop name.
        /// </param>
        public void NotifyPropertyChanged(string propName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propName));

                this.OnNodeUpdated(new EventArgs());
            }
        }

        /// <summary>
        /// The to string.
        /// </summary>
        /// <returns>
        /// The System.String.
        /// </returns>
        public override string ToString()
        {
            return this.Name;
        }

        #endregion

        #region Methods

        /// <summary>
        /// The load children.
        /// </summary>
        /// <returns>
        /// The System.Collections.Generic.IEnumerable`1[T -&gt; Tools.SqlServerDocGenerator.NodeViewModel].
        /// </returns>
        protected virtual IEnumerable<NodeViewModel> LoadChildren()
        {
            return new NodeViewModel[] { };
        }

        /// <summary>
        /// The on node updated.
        /// </summary>
        /// <param name="e">
        /// The e.
        /// </param>
        protected void OnNodeUpdated(EventArgs e)
        {
            if (this.NodeUpdated != null)
            {
                this.NodeUpdated(this, e);
            }
        }

        /// <summary>
        /// The child_ node updated.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void ChildNodeUpdated(object sender, EventArgs e)
        {
            // Propagate up
            this.OnNodeUpdated(e);
        }

        #endregion
    }
}